﻿using MvvmCross.Core.ViewModels;
using Sidvall.Data;
using Sidvall.IdentityManager.Data;
using Sidvall.IdentityManager.Security;
using Sidvall.IdentityManager.UI.Entities;
using Sidvall.IdentityManager.UI.Messaging;
using Sidvall.Security;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Sidvall.IdentityManager.UI.ViewModels
{
    public partial class AspNetUsersViewModel
    {
        #region Public Members

        #region Title

        public string Title
        {
            get
            {
                if (this.ActiveEntity == null)
                    return "User";
                return this.ActiveEntity.Name;
            }
        }

        #endregion
        #region IsCancelable

        public bool IsCancelable
        {
            get
            {
                if (!this.IsSavable)
                    return false;
                if (this.ActiveEntity.DataRowStateIsNew)
                    return false;
                return true;
            }
        }

        #endregion
        #region NewPassword

        private string _NewPassword;
        public string NewPassword
        {
            get
            {
                return _NewPassword;
            }
            set
            {
                _NewPassword = value;
                RaisePropertyChanged("NewPassword");
                RaisePropertyChanged("CanResetPassword");
            }
        }

        #endregion
        #region VerifyPassword

        private string _VerifyPassword;
        public string VerifyPassword
        {
            get
            {
                return _VerifyPassword;
            }
            set
            {
                _VerifyPassword = value;
                RaisePropertyChanged("VerifyPassword");
                RaisePropertyChanged("CanVerifyPassword");
            }
        }

        #endregion
        #region CanResetPassword

        public bool CanResetPassword
        {
            get
            {
                if (this.ActiveEntity == null)
                    return false;
                if (this.ActiveEntity.DataRowStateIsNew)
                    return false;
                if (string.IsNullOrWhiteSpace(this.NewPassword))
                    return false;
                return true;
            }
        }

        #endregion
        #region CanVerifyPassword

        public bool CanVerifyPassword
        {
            get
            {
                if (this.ActiveEntity == null)
                    return false;
                if (this.ActiveEntity.DataRowStateIsNew)
                    return false;
                if (string.IsNullOrWhiteSpace(this.VerifyPassword))
                    return false;
                return true;
            }
        }

        #endregion
        #region UserClaims

        public IEnumerable<AspNetUserClaims> UserClaims
        {
            get
            {
                if (this.ActiveEntity?.AspNetUserClaims == null)
                    return null;
                return (from o in this.ActiveEntity.AspNetUserClaims
                        where !o.ClaimType.Equals(Sidvall.Security.ClaimTypes.Name, System.StringComparison.OrdinalIgnoreCase)
                        select o);
            }
        }

        #endregion
        #region Claims

        private Sidvall.Security.ClaimCollection _Claims;
        public Sidvall.Security.ClaimCollection Claims
        {
            get
            {
                if (_Claims == null)
                    this.Claims = new ClaimCollection();
                return _Claims;
            }
            set
            {
                _Claims = value;
                RaisePropertyChanged(nameof(Claims));
            }
        }

        #endregion
        #region Plugin1

        public Plugin Plugin1
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetEditViewPlugin(0);
            }
        }

        #endregion
        #region Plugin2

        public Plugin Plugin2
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetEditViewPlugin(1);
            }
        }

        #endregion
        #region Plugin3

        public Plugin Plugin3
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetEditViewPlugin(2);
            }
        }

        #endregion
        #region Plugin4

        public Plugin Plugin4
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetEditViewPlugin(3);
            }
        }

        #endregion
        #region Plugin5

        public Plugin Plugin5
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetEditViewPlugin(4);
            }
        }

        #endregion

        // Claims
        #region AddUserClaim

        public ICommand AddUserClaimCommand
        {
            get
            {
                return new MvxCommand(AddUserClaim);
            }
        }
        public void AddUserClaim()
        {
            if (this.ActiveEntity == null)
                return;
            var item = new AspNetUserClaims()
            {
                ClaimType = Sidvall.Security.ClaimTypes.Role,
            };
            this.ActiveEntity.AspNetUserClaims.Add(item);
        }

        #endregion
        #region DeleteUserClaim

        public ICommand DeleteUserClaimCommand
        {
            get
            {
                return new MvxCommand<AspNetUserClaims>(DeleteUserClaim);
            }
        }
        public void DeleteUserClaim(AspNetUserClaims item)
        {
            if (this.ActiveEntity == null)
                return;
            if (item == null)
                return;
            this.ActiveEntity.AspNetUserClaims.Remove(item);
        }

        #endregion

        // Logins
        #region AddUserLogin

        public ICommand AddUserLoginCommand
        {
            get
            {
                return new MvxCommand(AddUserLogin);
            }
        }
        public void AddUserLogin()
        {
            AspNetUserLogins item;

            if (this.ActiveEntity == null)
                return;

            item = new AspNetUserLogins()
            {
            };
            this.ActiveEntity.AspNetUserLogins.Add(item);
        }

        #endregion
        #region DeleteUserLogin

        public ICommand DeleteUserLoginCommand
        {
            get
            {
                return new MvxCommand<AspNetUserLogins>(DeleteUserLogin);
            }
        }
        public void DeleteUserLogin(AspNetUserLogins item)
        {
            if (this.ActiveEntity == null)
                return;
            if (item == null)
                return;
            this.ActiveEntity.AspNetUserLogins.Remove(item);
        }

        #endregion

        // Security
        #region ResetPassword

        public ICommand ResetPasswordCommand
        {
            get
            {
                return new MvxCommand(async () => await ResetPasswordAsync());
            }
        }
        public async Task ResetPasswordAsync()
        {
            using (var busyManager = new BusyManager(this))
            {
                try
                {
                    await Sidvall.IdentityManager.SystemContext.Current.DataPortal.AspNetUsersManager.ResetPasswordAsync(this.ActiveEntity.Id, this.NewPassword);
                    this.NewPassword = string.Empty;
                    await DoLoadAsync();
                }
                catch (System.Exception ex)
                {
                    await Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Unexpected Error", ex);
                }
            }
        }

        #endregion
        #region VerifyPassword

        public ICommand VerifyPasswordCommand
        {
            get
            {
                return new MvxCommand(async () => await VerifyPasswordAsync());
            }
        }
        public async Task VerifyPasswordAsync()
        {
            PasswordVerificationResult result;

            using (var busyManager = new BusyManager(this))
            {
                try
                {
                    result = await Sidvall.IdentityManager.SystemContext.Current.DataPortal.AspNetUsersManager.VerifyUserPasswordAsync(this.ActiveEntity.Id, this.VerifyPassword);
                    switch (result)
                    {
                        case PasswordVerificationResult.Failed:
                            await Sidvall.UI.SystemContext.Current.DialogManager.ShowMessageAsync("Failed", result.ToString(), Sidvall.UI.Dialogs.MessageType.Error);
                            break;
                        default:
                            await Sidvall.UI.SystemContext.Current.DialogManager.ShowMessageAsync("Success", result.ToString(), Sidvall.UI.Dialogs.MessageType.Information);
                            break;
                    }
                }
                catch (System.Exception ex)
                {
                    await Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Unexpected Error", ex);
                }
            }
        }

        #endregion
        #region SendResetPasswordEmail

        public ICommand SendResetPasswordEmailCommand
        {
            get
            {
                return new MvxCommand(async () => await SendResetPasswordEmailAsync());
            }
        }
        public async Task SendResetPasswordEmailAsync()
        {
            using (var busyManager = new BusyManager(this))
            {
                try
                {
                    await Sidvall.IdentityManager.SystemContext.Current.DataPortal.AspNetUsersManager.SendResetPasswordEmailAsync(this.ActiveEntity.Id);
                }
                catch (System.Exception ex)
                {
                    await Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Unexpected Error", ex);
                }
            }
        }

        #endregion

        #region LoadItemAsync

        protected override async Task<AspNetUsers> LoadItemAsync()
        {
            AspNetUsers item;
            string id;

            if ((this.ActiveEntity != null) && (this.ActiveEntity.Id != null))
            {
                id = this.ActiveEntity.Id;
            }
            else
            {
                id = this.UserParameter.UserId;
            }
            if (id != null)
            {
                item = await SystemContext.Current.DataPortal.AspNetUsersManager.GetItemByPrimaryKeyAsync(id);
            }
            else
            {
                item = new AspNetUsers();
            }
            await item.LoadAspNetUserClaimsAsync();
            await item.LoadAspNetUserLoginsAsync();

            return item;
        }

        #endregion
        #region OnActiveEntityChanged

        protected override void OnActiveEntityChanged(Sidvall.Business.BusinessObjectChangeMode changeMode, Sidvall.Business.ChildChangedEventArgs childArgs, System.ComponentModel.PropertyChangedEventArgs propertyArgs)
        {
            if (!this.EventsIsEnabled)
                return;
            switch (changeMode)
            {
                case Sidvall.Business.BusinessObjectChangeMode.PropertyChanged:
                    PublishPlugins(UserMessageType.UserModified);
                    break;
                case Sidvall.Business.BusinessObjectChangeMode.NewBusinessObject:
                    PublishPlugins(UserMessageType.NewUser);
                    break;
                default:
                    break;
            }
            RaiseAllPropertiesChanged();
        }

        #endregion
        #region OnSaveItemCompleted

        protected override void OnSaveItemCompleted(Sidvall.Business.DataPortalContext<AspNetUsers, AspNetUsers> dataPortalContext)
        {
            switch (dataPortalContext.Result)
            {
                case Sidvall.Business.DataPortalResult.Failed:
                    break;
                default:
                    PublishPlugins(UserMessageType.UserSaved);
                    this.IsSavable = false;
                    break;
            }
        }

        #endregion
        #region OnIsSavableChanged

        protected override void OnIsSavableChanged()
        {
            RaisePropertyChanged("IsCancelable");
        }

        #endregion

        #region Init

        public void Init(UserParameter item)
        {
            this.UserParameter = item;
        }

        #endregion
        #region StartAsync

        protected async override Task StartAsync()
        {
            this.EventsIsEnabled = true;
            this.PublishChange = true;

            Sidvall.IdentityManager.Data.ClaimManager.Initialize(this.Claims);
            await ViewModelManager.LoadCacheAsync(false, GetLoadTasks(), this.EntityCache);
            await DoLoadAsync();
            Subscribe<PluginMessage>(OnPluginMessage);
            InitializePlugins();
        }

        #endregion

        #endregion
        #region Private Members

        private UserParameter UserParameter { get; set; }
        private bool EventsIsEnabled { get; set; }
        private bool PublishChange { get; set; }

        #region GetLoadTasks

        private ICollection<Task> GetLoadTasks()
        {
            System.Collections.Generic.List<Task> tasks;

            tasks = new System.Collections.Generic.List<Task>();
            return tasks;
        }

        #endregion
        #region InitializePlugins

        private void InitializePlugins()
        {
            Plugin plugin;
            ContextParameter parameter;
            int iMax;

            iMax = Sidvall.IdentityManager.UI.SystemContext.Current.EditViewPluginCount;
            for (int i = 0; i < iMax; i++)
            {
                plugin = Sidvall.IdentityManager.UI.SystemContext.Current.ValidEditViewPlugins[i];
                parameter = new ContextParameter()
                {
                    PluginId = plugin.PluginId.ToString(),
                };
                if (this.ActiveEntity != null)
                    parameter.UserId = this.ActiveEntity.Id;
                ShowViewModel(plugin.PluginInstance.EditViewModelType, parameter, false, "CenterContent.PluginContent" + (i + 1).ToString());
            }
            RaiseAllPropertiesChanged();
        }

        #endregion
        #region OnPluginMessage

        private void OnPluginMessage(PluginMessage obj)
        {
            if (this.ActiveEntity == null)
                return;
            switch (obj.PluginMessageType)
            {
                case PluginMessageType.UserModified:
                    this.IsSavable = true;
                    break;
                default:
                    break;
            }
        }

        #endregion
        #region PublishPlugins

        private UserMessage PublishPlugins(UserMessageType type)
        {
            if (this.ActiveEntity == null)
                return null;
            if (!this.PublishChange)
                return null;
            var contextMessage = new UserMessage(this)
            {
                UserId = this.ActiveEntity.Id,
                UserMessageType = type,
            };
            Publish(contextMessage);
            return contextMessage;
        }

        #endregion

        #endregion
    }
}